package com.wechat.admin.filter;

import com.wechat.admin.common.CommonConstants;
import com.wechat.admin.service.impl.CustomerUserDetailService;
import com.wechat.admin.service.impl.TokenBlacklistServiceImpl;
import com.wechat.admin.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;

/**
 * @Author:sjb
 * @CreateTime:2024-12-14
 * @Description: jwt认证过滤器和验证Token
 * @Version：1.0
 */
@Slf4j
//@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    private final CustomerUserDetailService userDetailsService;

    @Resource
    private TokenBlacklistServiceImpl tokenBlacklistService;


    public JwtAuthenticationFilter(CustomerUserDetailService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain)
            throws ServletException, IOException {

        String authHeader = httpServletRequest.getHeader(CommonConstants.AUTHORIZATION);
        if (authHeader != null && authHeader.startsWith(CommonConstants.TOKEN_PREFIX)) {
            // 提取token
            String token = authHeader.substring(7);

            // 检查 Token 是否在黑名单中
            if (tokenBlacklistService.isTokenBlacklisted(token)) {
                httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                httpServletResponse.getWriter().write("Token 已失效");
                return;
            }

            try {
                Claims claims = JwtUtil.validateToken(token);
                String username = claims.getSubject();
                if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                    UserDetails userDetails = userDetailsService.loadUserByUsername(username);
                    if(userDetails != null && isTokenValid(claims,userDetails)){
                        //  创建验证对象
                        UsernamePasswordAuthenticationToken authentication =
                                new UsernamePasswordAuthenticationToken(userDetails,null,userDetails.getAuthorities());
                        // 设置认证到securityContext中
                        SecurityContextHolder.getContext().setAuthentication(authentication);
                    }
                }
                httpServletRequest.setAttribute("claims", claims);
            } catch (Exception e) {
                httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                httpServletResponse.getWriter().write("invalid or expired token");
                return;
            }
        }
        filterChain.doFilter(httpServletRequest, httpServletResponse);
    }

    public static boolean isTokenValid(Claims claims, UserDetails userDetails) {
        return !isTokenExpired(claims) && claims.getSubject().equals(userDetails.getUsername());
    }

    private static boolean isTokenExpired(Claims claims) {
        return claims.getExpiration().before(new Date());
    }
}
